package com.cow.framework.core.websocket;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.cow.framework.core.exception.BusinessException;
import com.cow.framework.core.message.Message;
import com.cow.framework.core.message.MessageService;
import com.cow.framework.utils.cache.EhcacheUtil;
import com.cow.framework.utils.json.JsonUtil;
import com.cow.sram.comm.config.constant.MessageConstants;
import com.cow.sram.data.dto.UserSessionModel;

/**
 * ServerEndpoint
 * <p>
 * 使用springboot的唯一区别是要@Component声明下，而使用独立容器是由容器自己管理websocket的，但在springboot中连容器都是spring管理的。
 * <p>
 * 虽然@Component默认是单例模式的，但springboot还是会为每个websocket连接初始化一个bean，所以可以用一个静态set保存起来。
 *
 * @author sam
 * @since 2017/9/13
 */
@ServerEndpoint(value="/ws/message/{token}",configurator = CustomSpringConfigurator.class) //WebSocket客户端建立连接的地址
@Component
public class MessageServerEndpoint{
	@Autowired
	private MessageService messageService;
	@Autowired
	protected EhcacheUtil cacheUtil;
    /**
     * 存活的session集合（使用线程安全的map保存）
     */
    private static Map<String, Session> livingSessions = new ConcurrentHashMap<>();

    /**
     * 建立连接的回调方法
     *
     * @param session  与客户端的WebSocket连接会话
     * @param userName 用户名，WebSocket支持路径参数
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("token") String token) {    
    	try{    		
    		 //获取用户信息
            UserSessionModel user = (UserSessionModel)cacheUtil.getValue("userSession" , token);
            if(user == null){
            	throw new BusinessException("B1000",MessageConstants.B1000);
        	}
            livingSessions.put(user.getUserInfo().getUserid().toString(), session);
            sendMessage(session, "已建立连接!");
    	} catch (Exception e) {
            e.printStackTrace();
        }
       
    }

    /**
     * 收到客户端消息的回调方法
     *
     * @param message 客户端传过来的消息
     * @param session 对应的session
     */
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("token") String token) {    	
        sendMessageToAll(token + " : " + message);
    }


    /**
     * 发生错误的回调方法
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    /**
     * 关闭连接的回调方法
     */
    @OnClose
    public void onClose(Session session, @PathParam("token") String token) {
        livingSessions.remove(session.getId());
    }
    
     
    /**
     * 单独发送消息
     *
     * @param session
     * @param message
     * @throws IOException 
     */
    public void sendMessage(Session session, String message) throws IOException {
         session.getBasicRemote().sendText(message);
    }
    
    /**
     * 轮询发送消息
     *
     * @param session
     * @param message
     */
    @Scheduled(fixedRate=30000) 
    public void sendMessageToUser() {
    	if(!livingSessions.isEmpty()){
    		//获取未推送消息
        	List<Message> messageList = messageService.getNoPushMessage();
    		if(messageList != null && !messageList.isEmpty()){        			
    			for(Message m:messageList){
    				Session session = livingSessions.get(m.getReceiver().toString());
    				try{
    					if(session != null){
    						Map messageMap = new HashMap();
    	        			messageMap.put("message", m);
    	        			//获取未读消息数
    	        			Integer count = messageService.countNoRead(m.getReceiver());
    	        			messageMap.put("noReadNum", count);
    						sendMessage(session, JsonUtil.toJson(messageMap));
            				m.setStatus(1);//已推送
    					}
    	    		}catch (Exception e) {
    	    			livingSessions.remove(m.getReceiver().toString());
    	                continue;
    	            }        				
    			}        			        			
    			messageService.saveMessage(messageList);
    		}      
    	}		
    }
    
    /**
     * 群发消息
     *
     * @param message
     */
    public void sendMessageToAll(String message) {
        livingSessions.forEach((sessionId, session) -> {
            try {
				sendMessage(session, message);
			} catch (IOException e) {
				e.printStackTrace();
			}
        });
    }
    
    /**删除过期消息*/
    @Scheduled(fixedRate=86400000) 
    public void delExpiredMessage() {
    	messageService.delExpiredMessage();
    }

}